package com.users.controller;

import com.commons.annotations.RequiredToken;
import com.commons.enums.ResponseCodeEnum;
import com.commons.exception.GlobalExceptionHandler;
import com.commons.utils.MD5Tools;
import com.commons.utils.ResponseResult;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.users.dto.MsgLogin;
import com.users.dto.UserLogin;
import com.users.entity.Users;
import com.users.service.UsersService;
import com.users.utils.AvatarRandom;
import com.users.utils.VerifyCodeUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

import static com.commons.utils.Constance.*;

/**
 * @author mis_wu
 */
@RestController
@RequestMapping("/users-services")
@SuppressWarnings("unchecked")
@Api(tags = "Users-Service-Api 用户微服务接口")
@ControllerAdvice
@RefreshScope
public class UserController extends GlobalExceptionHandler {

    private static final Logger log = LoggerFactory.getLogger(UserController.class);

    private static final String TOKEN = "token";

    @Autowired
    private UsersService usersService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 用户注册
     * @param users
     * @param userPic
     * @param request
     * @return
     * @throws IOException
     * md5加密
     */
    @ApiOperation("用户注册")
    @ApiOperationSupport(author = "wubo")
    @PostMapping("/userregister")
    public synchronized ResponseResult userRegister(Users users, @RequestParam(required = false) MultipartFile userPic, HttpServletRequest request) throws IOException {
        String servePath="F:\\Vue-pro-model\\cloud-admin\\cloud-users\\src\\main\\resources\\userpic";
        //isEmpty()失效
        if (userPic == null){
            String avatar=new AvatarRandom().getAvatarPath();
            users.setPic(avatar);
        }else {
            String avatarName=userPic.getOriginalFilename();
            String newName=System.currentTimeMillis()+avatarName.substring(avatarName.lastIndexOf("."));
            userPic.transferTo(new File(servePath,avatarName));
            users.setPic(servePath+"\\"+avatarName);
        }
        log.info("currentuser {}",users);
        int res=usersService.saveUserInfo(users);
        if (res != 1){
            return new ResponseResult(ResponseCodeEnum.REGISTER_USER_EXIST.getCode(),ResponseCodeEnum.REGISTER_USER_EXIST.getMsg());
        }
        return new ResponseResult(ResponseCodeEnum.SUCCESS.getCode(),"注册成功!");
    }

    /**
     * 生成验证码
     */
    @ApiOperation("生成验证码")
    @GetMapping("/getImageCode")
    public void getImage(HttpSession session, HttpServletResponse response) throws IOException {
        //生成验证码
        String securityCode = VerifyCodeUtils.getSecurityCode();
        //将验证码放入session
        session.setAttribute("user_code",securityCode);
        //生成图片
        BufferedImage image = VerifyCodeUtils.createImage(securityCode);
        //输出图片
        ServletOutputStream outputStream = response.getOutputStream();

        //调用工具类
        ImageIO.write(image,"png",outputStream);
    }

    /**
     * 用户登陆
     * @param login
     * @param session
     * @return
     */
    @ApiOperation("用户账号密码登录")
    @PostMapping("/userlogin")
    public ResponseResult login(@ApiParam("用户登录信息") UserLogin login, HttpSession session) {
        Users users = usersService.selectByloginId(login.getLoginid());
        String token = session.getId();
        //解密密码
        String md5Pwd = MD5Tools.convertMD5(MD5Tools.convertMD5(users.getLoginPwd()));
        if (!ObjectUtils.isEmpty(users)) {
            if (users.getLoginPwd().equals(md5Pwd)) {
                //redisTemplate.setKeySerializer(new StringRedisSerializer());
                //赋原始密码
                users.setLoginPwd(md5Pwd);
                redisTemplate.opsForValue().set(TOKEN_KEY+token,users);
                session.setAttribute(CURR_USER,users);
                session.setAttribute("token",token);
                redisTemplate.expire(token, 60, TimeUnit.MINUTES);
                // 同上 设置有效期 redisTemplate.opsForValue().set(Constance.TOKEN_KEY+token,users,7,TimeUnit.DAYS);
                return new ResponseResult(ResponseCodeEnum.SUCCESS.getCode(),token);
            } else {
                return new ResponseResult(ResponseCodeEnum.FAIL.getCode(),"密码错误!");
            }
        } else {
            return new ResponseResult(ResponseCodeEnum.FAIL.getCode(),"用户名不存在!");
        }
    }

    /**
     * 验证码登陆
     * @param msgLogin
     * @param request
     * @return
     */
    @ApiOperation("用户短信验证码登录")
    @PostMapping("/userloginbyphone")
    public ResponseEntity loginByPhone(@RequestBody MsgLogin msgLogin, HttpServletRequest request) {
        //1、获取手机号
        String phone = msgLogin.getPhone();
        //2、获取验证码
        String captcha = msgLogin.getCaptcha();
        log.info("用户 手机号{} , 验证码{}", phone, captcha);
        String phoneKey = PHONE_KEY + phone;
        //3、点击发送验证码之后调用验证码服务cloud-sms,将phonekey存入redis
        //3-1、根据手机号判断redis中是否还存在手机号验证码,如果不存在说明已过期
        if (!stringRedisTemplate.hasKey(phoneKey)){
            throw new RuntimeException("提示:验证码已过期!");
        }
        //4、根据手机号获取redis中的验证码
        String redisCaptcha = stringRedisTemplate.opsForValue().get(phoneKey);
        //5、比较用户输入的验证码和redis中的是否一致
        if (!StringUtils.equals(captcha, redisCaptcha)) {
            throw new RuntimeException("提示:验证码输入错误!");
        }
        //6、判断是否为首次登录  判断手机号之前是否登录过
        Users users = usersService.findByPhone(phone);
        if (ObjectUtils.isEmpty(users)) {
            //新用户
            users = new Users("admin", "111", "hu zi", phone, "aci.jpg");
            //保存新用户信息
            usersService.insert(users);
        }
        String token = request.getSession().getId();
        //TOKEN_token
        String tokenKey = TOKEN_KEY + token;
        log.info("生成的token:{}", token);
        redisTemplate.opsForValue().set(tokenKey, users, 7, TimeUnit.DAYS);
        return new ResponseEntity(token, HttpStatus.OK);
    }

    /**
     * 退出
     * @param token
     * @param session
     * @return
     */
    @ApiOperation("退出登录")
    @PostMapping("/userlogout/{token}")
    public boolean loginout(@ApiParam("登录token") @PathVariable String token,HttpSession session) {
        Boolean delete=redisTemplate.delete(TOKEN_KEY+token);
        session.removeAttribute("token");
        session.removeAttribute(CURR_USER);
        if (delete) {
            return true;
        }
        return false;
    }

    /**
     * 登出
     * @param token
     * @param session
     * @return
     */
    @ApiOperation("注销登陆")
    @DeleteMapping("/userloginout")
    public ResponseEntity loginout2(String token,HttpSession session) {
        //根据token删除redis中用户信息
        redisTemplate.delete(TOKEN_KEY+token);
        session.removeAttribute("token");
        session.removeAttribute(CURR_USER);
        return new ResponseEntity(HttpStatus.NO_CONTENT);
    }

    /**
     * 方法一
     * @param token
     * @return
     */
    @ApiOperation("1-获取当前登录的用户信息")
    @GetMapping("/getcurruserinfo")
    public ResponseEntity<Users> getCurrUserInfo(@ApiParam("登录token") String token) {
        // 根据token获取对应信息
        Users users = (Users) redisTemplate.opsForValue().get(TOKEN_KEY + token);
        return new ResponseEntity<Users>(users, HttpStatus.OK);
    }

    /**
     * 方法二(使用拦截器是因为很多地方会用到用户信息) 请求实例:url?token=
     * @param request
     * @return
     * @throws JsonProcessingException
     * @RequiredToken //加了此注解的方法走拦截器的判断
     */
    @ApiOperation("2-获取当前登录的用户信息")
    @RequiredToken
    @GetMapping("/getcurruserinfo2")
    public ResponseEntity<Users> getCurrUserInfo2(HttpServletRequest request) throws JsonProcessingException {
        // 获取上下文中用户信息 TokenInterceptor
        Users users = (Users) request.getAttribute("curruser");
        log.info("userController获取的用户信息 {}:", new ObjectMapper().writeValueAsString(users));
        return new ResponseEntity<Users>(users, HttpStatus.OK);
    }

    @ApiOperation("修改用户信息-账号密码登录")
    @RequiredToken
    @PostMapping("/updateuserinfo")
    public ResponseResult updateUserInfo(Users users,@RequestParam(required = false) MultipartFile userpic,HttpServletRequest request,HttpSession session) throws IOException {
        String token= (String) request.getAttribute("token");
        Users userOld= (Users) request.getAttribute("curruser");
        String path="F:\\Vue-pro-model\\cloud-admin\\cloud-users\\src\\main\\resources\\userpic";
        if (userpic!=null){
            String picname=userpic.getOriginalFilename();
            //String subfix= System.currentTimeMillis() +picname.substring(picname.lastIndexOf("."));
            users.setPic(path+"\\"+picname);
            userOld.setPic(path+"\\"+picname);
            userpic.transferTo(new File(path,picname));
        }
        if (token.equals(session.getAttribute(TOKEN))){
            int res=usersService.updateUserByLoginId(users);
            if (res!=1){
                return new ResponseResult(ResponseCodeEnum.FAIL.getCode(), ResponseCodeEnum.FAIL.getMsg());
            }
            if (!ObjectUtils.isEmpty(users.getNickName())){
                userOld.setNickName(users.getNickName());
            }
            if (!ObjectUtils.isEmpty(users.getTel())) {
                userOld.setTel(users.getTel());
            }
            redisTemplate.opsForValue().set(TOKEN_KEY+token,userOld,7, TimeUnit.DAYS);
            session.setAttribute(CURR_USER,users);
        }else {
            return new ResponseResult(ResponseCodeEnum.INVALID_TOKEN.getCode(),ResponseCodeEnum.INVALID_TOKEN.getMsg());
        }
        return new ResponseResult(ResponseCodeEnum.SUCCESS.getCode(),ResponseCodeEnum.SUCCESS.getMsg());
    }

}
